package com.zhanghe.study.java8.stream;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 归约和收集
 */
public class TestStreamApi4 {

    private static List<User> list = new ArrayList<>(
            Arrays.asList(
                    new User(1,"张三",18, (byte) 0),
                    new User(2,"李四",20, (byte) 1),
                    new User(3,"王五",16, (byte) 0),
                    new User(4,"赵六",25, (byte) 1),
                    new User(5,"张三",30, (byte) 0),
                    new User(6,"张三",8, (byte) 0)
            )
    );

    public static void main(String[] args) {
        System.out.println("======testReduce=========");
        testReduce();
        System.out.println("======testCollect=========");
//        testCollect();
        testCollect5();
    }

    /**
     * 归约  将流中元素反复结合起来，得到一个值
     * reduce(T identity, BinaryOperator<T> accumulator) /BinaryOperator<T> accumulator/U identity,
     *                  BiFunction<U, ? super T, U> accumulator,
     *                  BinaryOperator<U> combiner
     */
    public static void testReduce(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        // BinaryOperator  二元运算   R apply(T t, U u);
        int sum = list.stream().reduce((x, y) -> x+y).get();
        System.out.println(sum);
    }

    /**
     * 收集 collect -- 将流转换为其他形式 接收一个Collector接口的实现，用于给Stream中元素做汇总的方法
     */
    public static void testCollect(){
        // Collector是一个接口  有一个Collectors提供了各种转换方式
        List<String> strings = list.stream().map(User::getName).collect(Collectors.toList());
        System.out.println(strings);
    }

    public static void testCollect1(){
        // 使用summarizingInt可以获取个数、总和、平均值、最大值和最小值
        IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(User::getAge));
        // IntSummaryStatistics{count=6, sum=117, min=8, average=19.500000, max=30}
        System.out.println(summaryStatistics);
    }

    public static void testCollect2(){
        // summingInt用于求和
        Integer sum = list.stream().collect(Collectors.summingInt(User::getAge));
        System.out.println(sum);
    }

    public static void testCollect3(){
        // averagingInt用于计算平均值
        Double average = list.stream().collect(Collectors.averagingInt(User::getAge));
        System.out.println(average);
    }

    public static void testCollect4(){
        // joining用于连接字符串
        String join = list.stream().map(User::getName).collect(Collectors.joining(","));
        System.out.println(join);
    }

    public static void testCollect5(){
        // partitioningBy用于数据分区
        Map<Boolean,List<User>> join = list.stream().collect(Collectors.partitioningBy(user -> user.getSex() == 0));
        System.out.println(join);
    }

    static class User{
        private long id;
        private String name;
        private int age;
        private byte sex;

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", sex=" + sex +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return id == user.id &&
                    age == user.age &&
                    sex == user.sex &&
                    Objects.equals(name, user.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, name, age, sex);
        }

        public User(long id, String name, int age, byte sex){
            this.id = id;
            this.name = name;
            this.age = age;
            this.sex = sex;
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public byte getSex() {
            return sex;
        }

        public void setSex(byte sex) {
            this.sex = sex;
        }
    }
}
